﻿namespace wToggl
{
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;

    using Windows.Phone.UI.Input;
    using Windows.UI.Popups;
    using Windows.UI.ViewManagement;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;

    using wToggl.Common;

    using wToggle.Platform;
    using wToggle.Platform.Interfaces;

    using XPlatUtils;

    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class LoginPage : INotifyPropertyChanged
    {
        private NavigationHelper navigationHelper;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();

        private bool isLoggingIn;

        public LoginPage()
        {
            this.InitializeComponent();

            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
            this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
            this.DataContext = this;

            var statusBar = StatusBar.GetForCurrentView();

           this.NavigationCacheMode = NavigationCacheMode.Disabled;
            HardwareButtons.BackPressed -= this.HardwareButtonsOnBackPressed;
            HardwareButtons.BackPressed += this.HardwareButtonsOnBackPressed;

            // Hide the status bar
            statusBar.HideAsync();
        }

        private void HardwareButtonsOnBackPressed(object sender, BackPressedEventArgs backPressedEventArgs)
        {
            backPressedEventArgs.Handled = true;
            Application.Current.Exit();
        }

        /// <summary>
        /// Gets the <see cref="NavigationHelper"/> associated with this <see cref="Page"/>.
        /// </summary>
        public NavigationHelper NavigationHelper
        {
            get { return this.navigationHelper; }
        }

        /// <summary>
        /// Gets the view model for this <see cref="Page"/>.
        /// This can be changed to a strongly typed view model.
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        public bool IsLogginIn
        {
            get
            {
                return this.isLoggingIn;
            }

            set
            {
                this.isLoggingIn = value;
                this.OnPropertyChanged();
            }
        }

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="sender">
        /// The source of the event; typically <see cref="NavigationHelper"/>
        /// </param>
        /// <param name="e">Event data that provides both the navigation parameter passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested and
        /// a dictionary of state preserved by this page during an earlier
        /// session.  The state will be null the first time a page is visited.</param>
        private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
        }

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="sender">The source of the event; typically <see cref="NavigationHelper"/></param>
        /// <param name="e">Event data that provides an empty dictionary to be populated with
        /// serializable state.</param>
        private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {
        }

        #region NavigationHelper registration

        /// <summary>
        /// The methods provided in this section are simply used to allow
        /// NavigationHelper to respond to the page's navigation methods.
        /// <para>
        /// Page specific logic should be placed in event handlers for the  
        /// <see cref="NavigationHelper.LoadState"/>
        /// and <see cref="NavigationHelper.SaveState"/>.
        /// The navigation parameter is available in the LoadState method 
        /// in addition to page state preserved during an earlier session.
        /// </para>
        /// </summary>
        /// <param name="e">Provides data for navigation methods and event
        /// handlers that cannot cancel the navigation request.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            Analytics.ReportPageVisit(this);  
            this.navigationHelper.OnNavigatedTo(e);
            HardwareButtons.BackPressed -= this.HardwareButtonsOnBackPressed;
            HardwareButtons.BackPressed += this.HardwareButtonsOnBackPressed;
            
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            this.navigationHelper.OnNavigatedFrom(e);
            HardwareButtons.BackPressed -= this.HardwareButtonsOnBackPressed;
        }

        #endregion

        private async void StandardLoginButton_Click(object sender, RoutedEventArgs e)
        {
            if (!Toggly.HasInternetAccess())
            {
                this.Dispatcher.ShowMessage(
                    "Unable to connect to the internet. Verify your connection and try agian.",
                    "Toggly");
                return;
            }

            var dialog = new LoginDialog();

            var dialogResult = await dialog.ShowAsync();

            if (dialogResult == ContentDialogResult.Primary)
            {
                var username = dialog.Email;
                var password = dialog.Password;

                await this.LoginCore(username, password);
            }
        }

        private async void TokenLoginButton_Click(object sender, RoutedEventArgs e)
        {
            if (!Toggly.HasInternetAccess())
            {
                this.Dispatcher.ShowMessage(
                    "Unable to connect to the internet. Verify your connection and try agian.",
                    "Toggly");
                return;
            }

            var dialog = new LoginDialog(true);
            
            var dialogResult = await dialog.ShowAsync();
            
            if (dialogResult == ContentDialogResult.Primary)
            {
                await this.LoginCore(dialog.Password, "api_token");
            }
        }

        private async Task LoginCore(string username, string password)
        {
            this.IsLogginIn = true;

            var auth = ServiceContainer.Resolve<ITogglAuth>();
            var result = await auth.Authenticate(username, password);

            if (result == AuthStatus.Success)
            {
                var settings = ServiceContainer.Resolve<IApplicationSettings>();
                settings.Username = username;
                settings.Password = password;

                if (this.Frame.CanGoBack)
                {
                    this.Frame.GoBack();
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                var md =
                    new MessageDialog(
                        "Login attempt failed. Verify you provided the right login credentials and try again.",
                        "Login failed");
                await md.ShowAsync();
            }

            this.IsLogginIn = false;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private async void LoginPage_OnLoaded(object sender, RoutedEventArgs e)
        {
            var settings = ServiceContainer.Resolve<IApplicationSettings>();

            if (!string.IsNullOrEmpty(settings.Username) && !string.IsNullOrEmpty(settings.Password))
            {
                await this.LoginCore(settings.Username, settings.Password);
            }
        }
    }
}
